using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Pavilion;

namespace Pavilion.Control
{
    public class TextBox : Control
    {
        private List<char> characters;
        private Color textColor;
        private float textSize;
        private Allign textAllign;
        private Point cursorPosition;
        private int cursorTimer, cursorIndex;
        private bool select;

        public event Action<string> TextChanged;

        public TextBox(Rectangle bounds) : base()
        {
            AreaBounds = bounds;

            characters = new List<char>();

            cursorPosition = new Point();
            TextColor = Color.Black;
            TextSize = 0.3f;
            TextAllign = Allign.Left;

            this.Input.MousePress += new MouseObjectHandler(TextBox_MousePress);
            this.Input.OuterClick += new Action<MouseCursor>(TextBox_OuterClick);
            this.Input.KeyPressed += new Action<Keys[]>(TextBox_KeyPressed);
        }

        public override void Draw()
        {
            if (!Visible)
                return;

            DrawManager.Instance.FillRectangleOnScreen(ScreenBounds, BackgroundColor);
            DrawManager.Instance.DrawRectangleOnScreen(ScreenBounds, OutlineColor);

            if (TextAllign == Allign.Left)
                DrawManager.Instance.DrawTextOnScreen(Text, new Vector2(ScreenBounds.Left + 5, ScreenBounds.Top), TextColor, TextSize, false);
            else
                DrawManager.Instance.DrawTextOnScreen(Text, new Vector2(ScreenBounds.Left + ScreenBounds.Width / 2,
                    ScreenBounds.Top + ScreenBounds.Height / 2 + 3), TextColor, TextSize, true);

            if (Select)
            {
                if (cursorTimer < 20)
                    DrawManager.Instance.DrawTextOnScreen("|", new Vector2(ScreenBounds.Left + cursorPosition.X + 5, ScreenBounds.Top), TextColor, TextSize, false);

                cursorTimer++;
                if (cursorTimer > 40)
                    cursorTimer = 0;
            }
        }

        /// <summary>
        /// Serializes a key to a char value.
        /// </summary>
        /// <param name="key">The key that is to be serialized.</param>
        /// <param name="shiftDown">If the Shift button is down.</param>
        /// <returns></returns>
        private char SerializeKey(Keys key, bool shiftDown)
        {
            //Letters
            if (key.ToString().Length == 1)
            {
                if (shiftDown)
                    return key.ToString().ToUpper()[0];
                else
                    return key.ToString().ToLower()[0];
            }

            //Numbers
            if (key.ToString().Length == 2 && key.ToString()[0] == 'D')
                return key.ToString()[1];
            else if (key.ToString().Length == 7 && key.ToString().Substring(0, key.ToString().Length - 1) == "NumPad")
                return key.ToString()[6];

            if (Keys.OemMinus == key)
                return '-';
            else if (Keys.OemPeriod == key || Keys.Decimal == key)
                return '.';

            return ' ';
        }

        /// <summary>
        /// Gets or Sets the Text of this label.
        /// </summary>
        public string Text
        {
            get
            {
                string text = "";

                for (int i = 0; i < characters.Count; i++)
                    text += characters[i];

                return text;
            }
            set
            {
                characters.Clear();
                characters.AddRange(value.ToCharArray());

                if (cursorIndex >= characters.Count)
                    cursorIndex = characters.Count - 1;
            }
        }

            /// <summary>
            /// Gets or sets the size of the text.
            /// </summary>
            public float TextSize
        {
            get { return textSize; }
            set { textSize = value; }
        }

        /// <summary>
        /// Gets or sets the Color of the text.
        /// </summary>
        public Color TextColor
        {
            get { return textColor; }
            set { textColor = value; }
        }

        /// <summary>
        /// Gets or sets the Allignment of the text.
        /// </summary>
        public Allign TextAllign
        {
            get { return textAllign; }
            set { textAllign = value; }
        }

        /// <summary>
        /// Gets or sets whether the textBox is selected.
        /// </summary>
        private bool Select
        {
            get { return select; }
            set
            {
                select = value;

                if (!select)
                    OnTextChanged();
            }
        }

        private void OnTextChanged()
        {
            if (TextChanged != null)
                TextChanged(Text);
        }

        private void TextBox_MousePress(object sender, MouseCursor mouseCursor)
        {
            Vector2 charArea;
            string text = "";
            int i = 0;

            for (; i < characters.Count; i++)
            {
                charArea = DrawManager.Instance.GameFont.MeasureString(text);

                if (mouseCursor.Position.X - ScreenBounds.X - 5 < (charArea.X * TextSize))
                    break;

                text += characters[i];
            }
            cursorPosition.X = (int)(DrawManager.Instance.GameFont.MeasureString(text).X * TextSize);
            cursorIndex = i;

            Select = true;
        }

        private void TextBox_KeyPressed(Keys[] keys)
        {
            bool shiftPressed = false;

            if (!select)
                return;

            if (Keyboard.GetState().IsKeyDown(Keys.LeftShift) || Keyboard.GetState().IsKeyDown(Keys.RightShift))
                shiftPressed = true;

            if (Keyboard.GetState().IsKeyDown(Keys.Delete))
            {
                if (cursorIndex < characters.Count)
                    characters.RemoveAt(cursorIndex);
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Back))
            {
                if (cursorIndex != 0)
                {
                    characters.RemoveAt(cursorIndex - 1);
                    cursorIndex--;
                }
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Left))
            {
                if (cursorIndex > 0)
                    cursorIndex--;
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Right))
            {
                if (cursorIndex < characters.Count)
                    cursorIndex++;
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.Enter))
            {
                Select = false;
            }
            else
            {
                for (int i = 0; i < keys.Length; i++)
                {
                    if (keys[i] == Keys.RightShift || keys[i] == Keys.LeftShift)
                        continue;

                    if (keys[i] == Keys.Space)
                    {
                        characters.Insert(cursorIndex, ' ');
                        cursorIndex++;
                    }
                    else
                    {
                        char value = SerializeKey(keys[i], shiftPressed);

                        if (value != ' ')
                        {
                            characters.Insert(cursorIndex, value);
                            cursorIndex++;
                        }
                    }
                }
            }

            cursorPosition.X = (int)(DrawManager.Instance.GameFont.MeasureString(Text.Substring(0, cursorIndex)).X * TextSize);
        }

        private void TextBox_OuterClick(MouseCursor mouseCursor)
        {
            Select = false;
        }
    }
}
